#include "TcpServer.h"
#include "TcpConnection.h"
#include "ThreadPool.h"
#include <iostream>
#include <unistd.h>

using std::cout;
using std::endl;

ThreadPool *gPool = nullptr;//全局变量

class MyTask
{
public:
    MyTask(const string &msg, const TcpConnectionPtr &con)
    : _msg(msg)
    , _con(con)
    {

    }

    void process()
    {
        //就在这里进行处理_msg
        //完成业务逻辑的处理
        //decode
        //compute
        //encode
        //...
        //线程池在处理好数据之后，不能自己将数据发送给
        //客户端，而应该将数据发送给Reactor/EventLoop,
        //让Reactor将数据发送给客户端
        //问题就是：线程池什么时候将数据发送给Reactor？
        //答案：线程池将数据处理好之后就立马发给Reactor
        //但是Reactor不可能一直阻塞等待线程池的数据，
        //所以需要线程池通知一下Reactor可以接收数据了
        //
        //Q:那么线程池是线程，Reactor也是线程，那就说明
        //了线程之间需要进行通信把？那线程之间如何进行
        //通信呢？
        //A:线程/进程之间的通信方法有eventfd
        //
        //Q:eventfd怎么用？
        //数据msg已经处理好了，成为了可以发送给客户端的_msg
        _con->sendInLoop(_msg);
    }
private:
    string _msg;
    TcpConnectionPtr _con;
};

//连接建立做的事件
void onConnection(const TcpConnectionPtr &con)
{
    cout << con->toString() << " has connected!!" << endl; 
}

//消息到达做的事件
void onMessage(const TcpConnectionPtr &con)
{
    //接收客户端的数据
    string msg = con->receive();//读网络数据,Read,Input
    cout << ">>recv msg from client : " << msg << endl;

    //接收到客户端的数据之后，并没有将数据做处理，也就是
    //没有处理业务逻辑
    //如果业务逻辑的处理比较复杂，计算量比较大,需要CPU的
    //参数就越多
    //......
    //....
    //....
    MyTask task(msg, con);
    gPool->addTask(std::bind(&MyTask::process, task));
    /* gPool->addTask(std::bind(&MyTask::process, &task));//error */
}

//连接断开做的事件
void onClose(const TcpConnectionPtr &con)
{
    cout << con->toString() << " has closed!!!" << endl; 
}

void test()
{
    ThreadPool pool(4, 10);
    //启动线程池的目的就是为了去处理业务逻辑
    pool.start();
    gPool = &pool;

    TcpServer server("127.0.0.1", 8888);
    server.setAllCallback(std::move(onConnection), 
                          std::move(onMessage), 
                          std::move(onClose));
    server.start();

}

int main(int argc, char **argv)
{
    test();
    return 0;
}

